Skip to content

Rewrite type declarations#42

Open
JELoohuis wants to merge 12 commits intoathombv:masterfrom
JELoohuis:add-generic-types
Open

Rewrite type declarations#42
JELoohuis wants to merge 12 commits intoathombv:masterfrom
JELoohuis:add-generic-types

Conversation

@JELoohuis
Copy link
Copy Markdown

The data types did not yet reflect the actual type of data they contained, so I made the class definition generic and added a new DataTypes definition using it.

I also took the liberty to rewrite the other definitions based on the types we have built at @athombv/drenso, based on the JS source and runtime introspection.

@RobinBol RobinBol self-requested a review April 13, 2026 11:57
@RobinBol RobinBol self-assigned this Apr 13, 2026
Comment thread index.d.ts Outdated
Comment thread index.d.ts Outdated
Comment thread index.d.ts Outdated
Comment thread index.d.ts Outdated
Comment thread index.d.ts Outdated
Comment thread index.d.ts Outdated
Comment thread index.d.ts Outdated
Comment thread index.d.ts
Comment thread index.d.ts Outdated
Comment thread index.d.ts Outdated
@JELoohuis JELoohuis requested a review from RobinBol April 17, 2026 10:56
Split Bitmap class into BitmapBase + Bitmap type alias. The type alias
intersects the base class with a mapped type producing a boolean
property per declared flag, matching the runtime behavior where
Object.defineProperties adds named getters for each flag.

Non-null flag names filter via `K extends string ? K : never` so
`map8('a', null, 'b')` correctly excludes the null slot.

Before: accessing `bitmap.myFlag` errored with TS2339 even though it
works at runtime.
After: `bitmap.myFlag` resolves to `boolean`, matching runtime.
Allow a Struct to be used as a field value inside another Struct
definition. Previously the Defs generic was constrained to
Record<string, DataType<any>>, which rejected nested Structs with
"Type 'StaticStruct<...>' is missing the following properties from
type 'DataType<any>': id, shortName, args, defaultValue, ...".

Changes:
- Introduce StructField = DataType<any> | StaticStruct<any> for the
  field-value union.
- Widen the Defs constraint to Record<string, StructField> on Struct,
  StaticStruct, StructInstance, and StructProperties.
- Extend StructProperties with a second branch: when a field is a
  StaticStruct<InnerDefs>, it resolves to StructProperties<InnerDefs>
  recursively, so nested field access narrows correctly.
- Change StaticStruct.toBuffer value parameter from StructInstance<Defs>
  to StructProperties<Defs> so plain nested objects are accepted on
  write (the common case - you don't need to construct Struct instances
  just to serialize).

The "Structs in Structs are considered a no-go" known-limitation line
is removed from the usage example.

Nested reads now type as StructProperties (plain shape) instead of
StructInstance, so .toJSON() / .toBuffer() on nested fields are no
longer typed. This matches runtime: fromBuffer of an outer Struct
produces plain nested objects, not inner Struct class instances.
Top-level .toJSON()/.toBuffer() are unaffected.
DataTypes.Array8 (and Array0) already accepts a Struct at runtime -
arrayToBuf/arrayFromBuf only read .toBuffer, .fromBuffer, and .length
from the element type, which both DataType and StaticStruct provide.
The .d.ts however only typed the DataType case, so consumers hit
"Type 'StaticStruct<...>' is not assignable to parameter of type
'DataType<unknown>'" when passing a Struct.

Add an overload matching StaticStruct<Defs> that returns
DataType<Array<StructProperties<Defs>>>, so array-of-Struct narrows
to an array of plain field-shape objects and plain objects are
accepted on write. The DataType overload continues to handle
DataTypes.Array8(DataTypes.uint16) etc. unchanged.

Also extends the usage example in the doc block with an Array-of-Struct
snippet.
index.d.ts had no automated regression coverage. Silent widening or
narrowing of a type would only surface when a downstream consumer
upgrades and hits a compile error. Add a type-level test file that
exercises the public contract, plus CI wiring to run it.

- test/types-test.ts: 9 sections covering primitives (numbers,
  buffers, strings, bool | null, EUI/key), enum narrowing, Bitmap
  flag property access, Struct basics (create/read/write/typos),
  nested Structs and arrays, fromBuffer returnLength overload,
  StaticStruct metadata, encodeMissingFieldsBehavior option, and
  custom DataType via the exposed constructor. Uses positive type
  assertions and @ts-expect-error directives so the file fails to
  compile on any type regression in either direction.
- tsconfig.json: strict mode, noEmit, node16 module resolution.
  Mapped to the in-repo index.d.ts via paths so the tests run
  against the working copy.
- package.json: typecheck script (tsc --noEmit) and typescript
  devDependency (^5.6.3).
- .github/workflows/test.yml: separate Typecheck job on Node 20.
  The existing test matrix runs Node 12/16 which are too old for
  TypeScript 5.x (needs Node >= 14.17).
@RobinBol
Copy link
Copy Markdown
Contributor

Pushed 7 commits on top of your PR. Here's what changed:

Docs + style (small)

  • 655f817 Updated the TS usage example in the doc comment of index.d.ts
  • a283823 Standardized formatting of DataType declarations and function signatures in index.d.ts for consistency

Type fixes (behavior)

  • 0bfc54c Bitmap flag access - Split class Bitmap into class BitmapBase + type Bitmap = BitmapBase & {[K in Flags]: boolean} in index.d.ts. Consumers can now access bitmap.myFlag as boolean, matching the runtime Object.defineProperties behavior. Null flags are filtered out via K extends string ? K : never.
  • 8ea0d5e Simplified StructProperties definition in index.d.ts (moved inside the module block, dropped redundant import() references)

New features

  • 4853315 Structs in Structs - In index.d.ts: introduced StructField = DataType<any> | StaticStruct<any>, widened Defs constraint on Struct/StaticStruct/StructInstance/StructProperties, added recursive branch in StructProperties for nested Struct fields, changed StaticStruct.toBuffer value param to StructProperties<Defs> so plain nested objects work on write. Removes the "Structs in Structs are considered a no-go" known-limitation line.
  • ff92e21 Array of Structs - Added overloads on Array0/Array8 in index.d.ts that accept a StaticStruct and return DataType<Array<StructProperties<Defs>>>. The runtime already supported this (it only reads .toBuffer/.fromBuffer/.length from the element), the types just didn't cover it.

Test coverage

  • 65f9b34 Types test + CI - Added test/types-test.ts (9 sections covering primitive value types, enum narrowing, Bitmap, Struct basics, nested/array patterns, fromBuffer overload, StaticStruct metadata, encodeMissingFieldsBehavior, custom DataType via constructor). Uses positive assertions + @ts-expect-error directives so any type regression in either direction fails to compile. Added npm run typecheck (tsc --noEmit) to package.json, typescript devDep, tsconfig.json, and a separate Typecheck CI job in .github/workflows/test.yml on Node 20 (existing test matrix uses Node 12/16 which are too old for TS 5.x).

Can you review my changes?

@RobinBol RobinBol requested a review from nozols April 17, 2026 12:36
@JELoohuis
Copy link
Copy Markdown
Author

Looks good. I hadn't seen the method of overloading used for the Array datatypes before, so it threw me for a bit of a loop, but I also don't know of any way to make that more explicit without cluttering the namespace. Unless you know a clean solution I'll just add a comment for clarity.

@RobinBol
Copy link
Copy Markdown
Contributor

I think a comment is fine!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants